package com.learning.dubbo.features.async.consumer;

import com.learning.dubbo.features.async.api.GreetingsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * ClassName: Consumer
 * Description: 消费客户端
 * Date: 2020/6/15 13:43 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
@Slf4j
public class Consumer {
    public static void main(String[] args) throws Exception {
//        syncConsumer();
//        asyncConsumer();
        asyncRpcContextConsumer();
    }


    /**
     * 同步调用
     *
     * @throws InterruptedException
     * @throws java.util.concurrent.ExecutionException
     */
    private static void syncConsumer() throws InterruptedException, java.util.concurrent.ExecutionException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
        context.start();

        // 获取远程服务代理
        GreetingsService greetingsService = (GreetingsService) context.getBean("greetingsService");
        // 执行远程方法，同步方法
        String result = greetingsService.sayHi("Dubbo");
        // 显示调用结果
        log.info("~~~~~~~~~~~ {} ~~~~~~~~~~~~~", result);

        // 调用 CompletableFuture 异步执行的方法
        RpcContext.getContext().setAttachment("consumerkey1", "CompletableFuture");
        CompletableFuture<String> future = greetingsService.sayHello("CompletableFuture Dubbo method");
        result = future.get();
        log.info("~~~~~~~~~~~ {} ~~~~~~~~~~~~~", result);

        // 调用 AsyncContext  异步执行的方法
        result = greetingsService.sayHello2("AsyncContext Dubbo method");
        log.info("~~~~~~~~~~~ {} ~~~~~~~~~~~~~", result);
        // 代理对象
        log.info(greetingsService.getClass().getName());
        context.close();
    }


    /**
     * 异步调用。服务端需要 CompletableFuture，
     * 客户端正常使用即可，不需要配置。
     * 【推荐】
     */
    private static void asyncConsumer() throws InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
        context.start();

        GreetingsService greetingsService = (GreetingsService) context.getBean("greetingsService");

        RpcContext.getContext().setAttachment("consumerkey1", "CompletableFuture");
        CompletableFuture<String> future = greetingsService.sayHello("CompletableFuture Dubbo method");

        // 增加回调
        future.whenComplete((v, t) -> {
            if (t != null) {
                t.printStackTrace();
            } else {
                System.out.println(" ***************** Response: ************ " + v);
            }
        });

        // 早于结果输出
        System.out.println("~~~~~~~~ Executed before response return. ~~~~~~~~~~~~~~~~~");
        Thread.sleep(10000L);
    }

    /**
     * 使用 RpcContext
     * 1- 客户单配置 async="true"
     */
    private static void asyncRpcContextConsumer() throws InterruptedException, ExecutionException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
        context.start();

        GreetingsService greetingsService = (GreetingsService) context.getBean("asyncGreetingsService");

        // 此调用会立即返回 null
        String world = greetingsService.sayHi("world");
        System.out.println(world);

        // 拿到调用的Future引用，当结果返回后，会被通知和设置到此Future
        CompletableFuture<String> helloFuture = RpcContext.getContext().getCompletableFuture();

        // 为Future添加回调
        helloFuture.whenComplete((retValue, exception) -> {
            if (exception == null) {
                System.out.println(retValue);
            } else {
                exception.printStackTrace();
            }
        });

        // 早于结果输出
        System.out.println("~~~~~~~~ Executed before response return. ~~~~~~~~~~~~~~~~~");


        /*CompletableFuture<String> future = RpcContext.getContext().asyncCall(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return greetingsService.sayHi("oneway call request1");
            }
        });

        String s = future.get();
        System.out.println(s);*/
        Thread.sleep(10000L);
    }
}
